<?php
/**
 * File: ProjectPoints.php
 * Author: camy <375766145@qq.com>
 * Time: 2018/3/21 10:01
 */

namespace Common\Service;

use Exception;

class ProjectPoints extends Base
{
    /**
     * 生成分配表序列号
     * @return mixed
     */
    protected function uniqueSerial()
    {
        $model = M('projectPointsAllocate');
        $closure = function () {
            return generate_unique_serial('JF');
        };
        return $this->uniqueKey($model, 'serial', $closure);
    }

    /**
     * 获取分配详情(新增)
     * @param $projectId
     * @param $type
     * @return mixed
     */
    public function getAddAllocateParam($projectId, $type)
    {
        //分配人
        $user = user();
        //可分配积分
        if ($type == 1) {
            //实际
            $points = $user->points;
        } else {
            //预计
            $points = $user->pre_points;
        }
        if ($points == 0) {
            $this->error = '暂无可分配积分';
            return false;
        }
        //可分配成员
        $map['superior_id'] = $user->id;
        $map['user_id'] = $user->id;
        $map['_logic'] = 'or';
        $members = M('projectMember')
            ->alias('pm')
            ->join('left join user u on pm.user_id=u.id')
            ->field('pm.user_id,pm.user_type type,pm.user_remark remark,u.name,u.avatar,u.department,u.position')
            ->where(['pm.project_id' => $projectId])
            ->where(['_complex' => $map])
            ->select();
        if (!$members) {
            $this->error = '暂无可分配成员';
            return false;
        }
        if ($members) {
            foreach ($members as &$member) {
                //分配记录表id
                $member['allocate_record_id'] = 0;
                //增加分配状态:未分配
                $member['allocate_status'] = 0;
                //已分配积分
                $member['allocate_points'] = '';
                //驳回原因
                $member['allocate_reason'] = '';
            }
        }
        return ['points' => $points, 'members' => $members, 'show_allocate_button' => true];
    }

    /**
     * 获取分配详情
     * @param $id
     * @return mixed
     */
    public function getAllocateParam($id)
    {
        $allocate = M('projectPointsAllocate')->find($id);
        if (!$allocate) {
            $this->error = '分配记录不存在';
            return false;
        }
        $user = M('user')->find($allocate['allocate_user_id']);
        //可分配积分
        if ($allocate['points_type'] == 1) {
            //实际
            $points = $user['points'];
        } else {
            //预计
            $points = $user['pre_points'];
        }
        if ($points == 0) {
            $this->error = '暂无可分配积分';
            return false;
        }
        //可分配成员
        $members = M('projectPointsAllocateRecord')
            ->alias('ar')
            ->join('left join user u on ar.user_id=u.id')
            ->field('ar.id allocate_record_id,ar.user_id,ar.user_type type,ar.status,ar.points,ar.refuse_reason allocate_reason,ar.user_remark remark,
            u.name,u.avatar,u.department,u.position')
            ->where(['ar.allocate_id' => $id])
            ->select();
        if (!$members) {
            $this->error = '暂无可分配成员';
            return false;
        }
        $showAllocateButton = false;
        foreach ($members as &$member) {

            if ($member['status'] != 2) {
                //0或1-已分配
                $member['allocate_status'] = 1;
            } else {
                $showAllocateButton = true;
                //驳回-重新分配
                $member['allocate_status'] = 2;
            }
            $member['allocate_points'] = '';
            unset($member['status']);
        }
        return ['points' => $points, 'members' => $members, 'show_allocate_button' => $showAllocateButton];

    }

    /**
     * 创建分配单
     * @param $projectId
     * @param $type
     * @param $totalPoints
     * @return mixed
     */
    public function createAllocate($projectId, $type, $totalPoints)
    {
        $user = user();
        //首先-减去对应账户积分
        $data['id'] = $user->id;
        if ($type == 1) {
            //实际积分
            $data['points'] = $user->points - $totalPoints;
        } else {
            //预计积分
            $data['pre_points'] = $user->pre_points - $totalPoints;
        }
        $res = M('user')->save($data);
        if (!$res) {
            $this->error = '同步账户余额失败';
            return false;
        }
        //新增分配单
        $projectMember = M('projectMember')
            ->where(['project_id' => $projectId, 'user_id' => $user->id])
            ->find();
        $allocateData['serial'] = $this->uniqueSerial();
        $allocateData['project_id'] = $projectMember['project_id'];
        $allocateData['allocate_user_id'] = $projectMember['user_id'];
        $allocateData['points_type'] = $type;
        $allocateData['points'] = $totalPoints;
        if ($type == 1) {
            //实际积分需确认
            $allocateData['status'] = 0;
        } else {
            //预计积分不需要确认
            $allocateData['status'] = 1;
        }
        $allocateId = M('projectPointsAllocate')->add($allocateData);
        if (!$allocateId) {
            $this->error = '创建分配单失败';
            return false;
        }
        return $allocateId;
    }

    /**
     * 新增分配积分记录
     * @param $allocateId
     * @param $points
     * @param $userId
     * @param $userType
     * @param $userRemark
     * @return mixed
     */
    public function addAllocateRecord($allocateId, $points, $userId, $userType, $userRemark)
    {
        //分配表
        $allocate = M('projectPointsAllocate')->find($allocateId);
        //新增记录
        $recordData['allocate_id'] = $allocate['id'];
        $recordData['points_type'] = $allocate['points_type'];
        $recordData['project_id'] = $allocate['project_id'];
        $recordData['user_id'] = $userId;
        $recordData['user_type'] = $userType;
        $recordData['user_remark'] = strval($userRemark);
        $recordData['allocate_user_id'] = $allocate['allocate_user_id'];
        $recordData['points'] = $points;
        $recordData['status'] = $allocate['status'];
        //分配人类型
        $member = M('projectMember')
            ->where(['project_id' => $allocate['project_id'], 'user_id' => $allocate['allocate_user_id']])
            ->find();
        //分配类型
        if ($allocate['points_type'] == 1) {
            //实际积分
            if ($recordData['user_id'] == $recordData['allocate_user_id']) {
                //自己-账户余额
                $recordData['allocate_type'] = 0;
                //自己-冻结状态
                $recordData['status'] = 3;
            } else {
                //负责人分配-实际积分可分配账户余额
                if ($member['user_type'] == 2) {
                    $recordData['allocate_type'] = 1;
                } else {
                    //专业负责人分配-实际积分账户余额
                    $recordData['allocate_type'] = 0;
                }
            }
        } else {
            //预计积分
            $recordData['allocate_type'] = 2;
            //如果是项目负责人分配-增加专业负责人预计积分余额
            if ($member['user_type'] == 2) {
                $prePoints = M('user')
                    ->where(['id' => $userId])
                    ->getField('pre_points');
                $prePoints += $points;
                $res = M('user')
                    ->where(['id' => $userId])
                    ->save(['pre_points' => $prePoints]);
                if (!$res) {
                    return false;
                }
            }
        }
        $res = M('projectPointsAllocateRecord')->add($recordData);
        if (!$res) {
            $this->error = "创建分配记录失败";
            return false;
        }
        return $res;
    }

    /**
     * 重新分配积分记录
     * @param $recordId
     * @param $points
     * @return mixed
     */
    public function addAllocateRecordAgain($recordId, $points)
    {
        $recordData = M('projectPointsAllocateRecord')
            ->find($recordId);
        if ($recordData['points_type'] != 1) {
            $this->error = '分配类型错误';
            return false;
        }
        //判断分配人
        $userId = user()->id;
        if ($recordData['allocate_user_id'] != $userId) {
            $this->error = '分配人错误';
            return false;
        }
        //不是驳回状态
        if ($recordData['status'] != 2) {
            $this->error = '分配成员无法重新分配';
            return false;
        }
        //创建新分配记录
        unset($recordData['id'], $recordData['created_at'], $recordData['updated_at'], $recordData['refuse_reason']);
        if ($recordData['user_id'] = $userId) {
            $recordData['status'] = 3;//分配人冻结
            //修改分配表状态
            $res = M('projectPointsAllocate')
                ->where(['id' => $recordData['allocate_id']])
                ->save(['status' => 0]);
            if (!$res) {
                return false;
            }
        } else {
            $recordData['status'] = 0;//分配用户待确认
        }
        $recordData['points'] = $points;
        $res = M('projectPointsAllocateRecord')->add($recordData);
        if (!$res) {
            return false;
        }
        //减去分配人可分配积分
        $allocateUserPoints = M('user')->where(['id' => $userId])->getField('points');
        $allocateUserPoints -= $points;
        $res = M('user')
            ->where(['id' => $userId])
            ->save(['points' => $allocateUserPoints]);
        if (!$res) {
            return false;
        }
        //删除原来的分配记录
        $res = M('projectPointsAllocateRecord')
            ->where(['id' => $recordId])
            ->delete();
        if (!$res) {
            return false;
        }

        return true;


    }

    /**
     * 确认积分分配
     * @param $recordId
     * @return mixed;
     */
    public function confirmPoints($recordId)
    {
        $record = M('projectPointsAllocateRecord')->find($recordId);
        $userId = user()->id;
        if ($userId != $record['user_id'] && !IS_CLI) {
            $this->error = '只能操作您自己的积分';
            return false;
        }
        if ($record['points_type'] != 1) {
            $this->error = '积分类型错误';
            return false;
        }
        if ($record['status'] != 0) {
            $this->error = '此次分配已确认，请勿重复提交';
            return false;
        }
        try {
            M()->startTrans();
            //修改状态
            $res = M('projectPointsAllocateRecord')
                ->where(['id' => $recordId])
                ->save(['status' => 1]);
            if (!$res) {
                throw new Exception();
            }
            //根据分配类型增加余额
            if ($record['allocate_type'] == 0) {
                //实际积分账户余额
                $filed = 'balance';
            } else if ($record['allocate_type'] == 1) {
                //实际积分可分配余额
                $filed = 'points';
            } else {
                throw new Exception('分配类型错误');
            }
            $points = M('user')
                ->where(['id' => $record['user_id']])
                ->getField($filed);
            $points += $record['points'];
            $res = M('user')
                ->where(['id' => $record['user_id']])
                ->save([$filed => $points]);
            if (!$res) {
                throw new Exception();
            }
            //如果分配人分配记录存在，检查分配成员是否都已确认
            $allocateUserRecord = M('projectPointsAllocateRecord')
                ->where(['allocate_id' => $record['allocate_id'], 'user_id' => $record['allocate_user_id']])
                ->find();
            if ($allocateUserRecord) {
                $allAllocateRecordStatus = M('projectPointsAllocateRecord')
                    ->field('status')
                    ->where([
                        'allocate_id' => $record['allocate_id'],
                        'allocate_user_id' => $record['allocate_user_id'],
                        'user_id' => ['neq', $record['allocate_user_id']]
                    ])
                    ->select();
                //成员都已经确认
                if (count($allAllocateRecordStatus) == array_column_sum($allAllocateRecordStatus, 'status')) {
                    //修改分配人状态
                    $res = M('projectPointsAllocateRecord')
                        ->where(['id' => $allocateUserRecord['id']])
                        ->save(['status' => 1]);
                    if (!$res) {
                        throw new Exception();
                    }
                    //根据分配类型增加余额
                    if ($allocateUserRecord['allocate_type'] == 0) {
                        //实际积分账户余额
                        $allocateUserFiled = 'balance';
                    } else if ($record['allocate_type'] == 1) {
                        //实际积分可分配余额
                        $allocateUserFiled = 'points';
                    } else {
                        throw new Exception('分配类型错误');
                    }
                    $allocateUserPoints = M('user')
                        ->where(['id' => $record['user_id']])
                        ->getField($allocateUserFiled);
                    $allocateUserPoints += $record['points'];
                    $res = M('user')
                        ->where(['id' => $record['user_id']])
                        ->save([$allocateUserFiled => $allocateUserPoints]);
                    if (!$res) {
                        throw new Exception();
                    }
                    //更改分配单状态为已确认
                    $res = M('projectPointsAllocate')
                        ->where(['id' => $record['allocate_id']])
                        ->save(['status' => 1]);
                    if (!$res) {
                        throw new Exception();
                    }
                }
            }
            M()->commit();
            return true;
        } catch (Exception $e) {
            M()->rollback();
            return false;
        }

    }


    /**
     * 拒绝积分分配
     * @param $recordId
     * @param $reason
     * @return  mixed;
     */
    public function refusePoints($recordId, $reason)
    {
        $record = M('projectPointsAllocateRecord')->find($recordId);
        $userId = user()->id;
        if ($userId != $record['user_id']) {
            $this->error = '只能操作您自己的积分';
            return false;
        }
        if ($record['points_type'] != 1) {
            $this->error = '积分类型错误';
            return false;
        }
        if ($record['status'] != 0) {
            $this->error = '此次分配已确认，请勿重复提交';
            return false;
        }
        try {
            M()->startTrans();
            //修改用户记录状态
            $res = M('projectPointsAllocateRecord')
                ->where(['id' => $recordId])
                ->save(['status' => 2, 'refuse_reason' => strval($reason)]);
            if (!$res) {
                throw new Exception();
            }
            //退回用户金额
            $points = M('user')
                ->where(['id' => $record['allocate_user_id']])
                ->getField('points');
            $points += $record['points'];
            $res = M('user')
                ->where(['id' => $record['allocate_user_id']])
                ->save(['points' => $points]);
            if (!$res) {
                throw new Exception();
            }
            //更新分配单状态为被驳回
            $res = M('projectPointsAllocate')
                ->where(['id' => $record['allocate_id']])
                ->save(['status' => 2]);
            if (!$res) {
                throw new Exception();
            }
            //如果分配人分配记录存在且状态为冻结
            $allocateUserRecord = M('projectPointsAllocateRecord')
                ->where(['allocate_id' => $record['allocate_id'], 'user_id' => $record['allocate_user_id']])
                ->find();
            if ($allocateUserRecord && $allocateUserRecord['status'] == 3) {
                //修改分配人状态
                $allocateReason = '成员申述';
                $res = M('projectPointsAllocateRecord')
                    ->where(['id' => $allocateUserRecord['id']])
                    ->save(['status' => 2, 'refuse_reason' => strval($allocateReason)]);
                if (!$res) {
                    throw new Exception();
                }
                //退回分配人金额
                $points += $allocateUserRecord['points'];
                $res = M('user')
                    ->where(['id' => $allocateUserRecord['user_id']])
                    ->save(['points' => $points]);
                if (!$res) {
                    throw new Exception();
                }
                M()->commit();
                return true;
            }

        } catch (\Exception $e) {
            M()->rollback();
            return false;
        }
    }


}